
#ifndef __RSP_DEF__HEADER_FILE__
#define __RSP_DEF__HEADER_FILE__


#include "coid/comm/commtypes.h"
#include "coid/comm/str.h"
#include "coid/comm/binstream/binstream.h"

#include "update.h"
#include "fcb.h"

////////////////////////////////////////////////////////////////////////////////
extern ushort Grsp_version;

////////////////////////////////////////////////////////////////////////////////
//extern uint Gtouch;
#define SERVER_ONLY_BEGIN       if( !rsp_controller::current->client_side() ) {
#define SERVER_ONLY_END         }

#define CLIENT_ONLY_BEGIN       if( rsp_controller::current->client_side() ) {
#define CLIENT_ONLY_END         }

////////////////////////////////////////////////////////////////////////////////
#define MARK_OUT(m)             { fcb.set((uchar)(m)); }
#define MARK_IN(m)              { uchar c; fcr.get(c); DASSERT( (m) == c ); }


////////////////////////////////////////////////////////////////////////////////
extern binstream*   TLOG;
extern binstream*   CLOG;
extern binstream*   BLOG;

extern int LOG_Level;
#define LOG(lev)                if(lev<=LOG_Level)

void init_server_log();
void init_client_log( binstream* bin );


////////////////////////////////////////////////////////////////////////////////
struct rsp_tile;
struct rsp_s_connector;

template <class ObjInfo> struct fcb_container;

////////////////////////////////////////////////////////////////////////////////
///Base class for all rsp-managed objects
struct rsp_base
{
private:
    template<class> friend struct fcb_container;

    rsp_tile* tile;                         ///< tile on what the object currently resides
    uint slot;                              ///< id of the object in tile

    union {
    rsp_base* bound;                        ///< bound interpolated object (ref state client only)
    rsp_s_connector* conn;                  ///< bound net connector (server only)
    };

    ///Flags for \a foid member
    enum {
        fREQUEST_KILL                       = 1<<31,
        fREQUEST_RENEW                      = 1<<30,
        xOID                                = (1<23)-1,
    };
    uint foid;                              ///< flags and unique object id

private:
    bool should_die() const                 { return (foid & fREQUEST_KILL) != 0; }
    bool should_renew() const               { return (foid & fREQUEST_RENEW) != 0; }
    bool should_renew_clr()                 { bool rn = (foid & fREQUEST_RENEW) != 0;  foid &= ~fREQUEST_RENEW;  return rn; }

public:

    rsp_base();
    virtual ~rsp_base();

    uint oid() const                        { return foid & xOID; }

    rsp_tile* get_tile() const              { return tile; }
    uint get_slot() const                   { return slot; }

    ///Get fcb for frame to be commited, prefilling it with object id
    frame_command_buffer& fcb();

    ///Mark object required to fully replicate because of some background change
    void touch()                            { foid |= fREQUEST_RENEW; }

    //@{ methods overriden by the COMMAND_CLASS macro
    virtual void copy_constructor( const rsp_base& src ) = 0;
    virtual rsp_base* new_constructor() const = 0;
    virtual void dispatch( const uchar* pc, const uchar* pe ) = 0;
    virtual const token& class_name() const = 0;
    virtual const token& class_id() const = 0;
    //@}


    //@{ full state save&load methods
    virtual void state_save( frame_command_buffer& ) const = 0;
    virtual void state_load( frame_command_reader& ) = 0;
    //@}

    ///Per frame called method
    ///@return new rsp_tile* if moved to another tile, NULL otherwise
    virtual rsp_tile* frame()               { return 0; }


    rsp_base* create_bound_object()
    {
        if(!bound)
            bound = new_constructor();
        return bound;
    }

    ///Create new object of class
    static rsp_base* create_object( const token& clsid );
    
    ///Register this class
    static token register_class( const token& clsid, rsp_base* (*fn)() );

    ///Read command buffer sent by the client
    int read_cmd( uchar nst, uint ackstateid, const uchar* pd, const uchar* pe );
};


#endif //__RSP_DEF__HEADER_FILE__
